<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>代码加载和执行顺序(Code loading and execution sequence)</title>
  <!-- 
    JavaScript 的加载和执行顺序对于理解代码的运行机制至关重要。

    1. 加载阶段
    - 定义：在浏览器解析 HTML 文档时，JavaScript 文件会被加载。
      - 当浏览器遇到  `<script>`  标签时，会暂停解析 HTML，开始加载 JavaScript 文件。
      - 如果使用  `async`  或  `defer`  属性，加载过程会有所不同。

    2. 执行阶段
    - 定义：加载完成后，JavaScript 代码会被执行。
      - 代码从上到下顺序执行，遇到函数声明时将其提升，但不会执行函数体。
      - 变量声明会被提升到作用域顶部，但赋值不会。

    3. 异步加载
    - async 属性：
      - 定义：当使用  `async`  属性时，脚本会异步加载，不会阻塞 HTML 解析。
      - 执行顺序：脚本加载完成后立即执行，可能会在 DOM 完全构建之前执行。
    <script src="script.js" async></script>
    - defer 属性：
      - 定义：当使用  `defer`  属性时，脚本会在文档完全解析后执行。
      - 执行顺序：保证脚本按照在 HTML 中出现的顺序执行。
    <script src="script.js" defer></script>

    4. 函数调用与执行
    - 函数声明：
      - 在代码解析阶段，函数声明会被提升到作用域顶部，可以在声明之前调用。
    function myFunction() {
        console.log("函数声明");
    }
    myFunction(); // 可以在声明之前调用
    - 函数表达式：
      - 函数表达式不会被提升，只能在定义之后调用。
    const myFunc = function() {
        console.log("函数表达式");
    };
    // myFunc(); // 不能在声明之前调用

    5. 事件和回调
    - 定义：当事件被触发时，相关的回调函数会被执行。
    - 执行顺序：
      - 事件处理函数会在当前执行栈完成后执行。
    document.getElementById("myButton").addEventListener("click", function() {
        console.log("按钮被点击");
    });

    6. 总结
    - 加载阶段：JavaScript 文件在 HTML 解析时被加载，使用  `async`  和  `defer`  属性可以控制加载顺序。
    - 执行阶段：代码从上到下执行，函数声明会被提升，变量声明也会提升但赋值不会。
    - 异步加载：使用  `async`  和  `defer`  属性可以优化页面加载性能。
    - 函数调用：注意函数声明和表达式的提升行为。
    - 事件处理：事件回调在当前执行栈完成后执行。

  -->
</head>
<body>

  <h1 class="title">代码加载和执行顺序(Code loading and execution sequence)</h1>
  <p> 当浏览器遇到  `script`  标签时，会暂停解析 HTML，开始加载 JavaScript 文件。
      如果使用  `async`  或  `defer`  属性，加载过程会有所不同。</p>

  <button id="myButton">事件和回调</button>
  
  <script>
    // 1.加载阶段
    {
      let titleEl = document.querySelector(".title");
      titleEl.style.color = "red";

      alert(titleEl.textContent) // 先执行alert，当浏览器遇到  `script`  标签时，会暂停解析 HTML，开始加载 JavaScript 文件
    }

    // 2.执行阶段
    {
      function myFunction() {
        console.log("函数声明");
      }
      myFunction(); // 可以在声明之前调用
      // 函数表达式：- 函数表达式不会被提升，只能在定义之后调用。

      // myFunc(); // 不能在声明之前调用
      const myFunc = function() {
        console.log("函数表达式");
      };
    }

    // 3.异步加载
    {
      // async: 异步加载，加载完成后立即执行
      // defer: 异步加载，等待 HTML 解析完成后执行
      // async 和 defer 的区别在于执行时机，async 是加载完成后立即执行，defer 是等待 HTML 解析完成后执行。
    }

    // 4.函数调用
    {
      document.getElementById("myButton").addEventListener("click", function() {
          console.log("按钮被点击-事件和回调");
      });
    }
  </script>
  
</body>
</html>